package com.yyfax.pay.depository.service.inner.impl;

import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import com.yyfax.commons.json.FastJsonUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.pay.common.constants.PayConstants;
import com.yyfax.pay.common.enums.FuiouBusiTypeEnum;
import com.yyfax.pay.common.enums.TaskStateEnum;
import com.yyfax.pay.depository.dao.FuiouNotifyTaskDao;
import com.yyfax.pay.depository.dao.FuiouQueryTaskDao;
import com.yyfax.pay.depository.domain.FuiouNotifyTask;
import com.yyfax.pay.depository.domain.FuiouQueryTask;
import com.yyfax.pay.depository.service.inner.FuiouDepositCommonService;
import com.yyfax.pay.quartz.dynamic.DynamicSchedulerFactory;
import com.yyfax.pay.quartz.jobs.FuiouDepositNotifyJob;
import com.yyfax.pay.quartz.jobs.FuiouDepositQueryJobDispatcher;
import com.yyfax.pay.quartz.model.vo.DynamicJobVO;

@Service
public class FuiouDepositCommonServiceImpl implements FuiouDepositCommonService {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Resource
	private PayConstants payConstants;

	@Resource
	private FuiouNotifyTaskDao fuiouNotifyTaskDao;

	@Resource
	private FuiouQueryTaskDao fuiouQueryTaskDao;

	@Override
	public void saveNotifyTask(String merchantCode, String orderId, String busiId, FuiouBusiTypeEnum busiType, String notifyUrl, String reqContent,
			Date startTime, Date endTime) {
		saveNotifyTask(merchantCode, orderId, busiId, busiType, notifyUrl, null, reqContent, startTime, endTime);
	}

	@Override
	public void saveNotifyTask(String merchantCode, String orderId, String busiId, FuiouBusiTypeEnum busiType, String notifyUrl,
			Map<String, String> reqHeader, String reqContent, Date startTime, Date endTime) {
		try {
			FuiouNotifyTask task = new FuiouNotifyTask();
			task.setBusiId(busiId);
			task.setType(busiType.getValue());
			task.setMerchantCode(merchantCode);
			task.setOrderId(orderId);
			task.setReqUrl(notifyUrl);
			task.setReqHeader(reqHeader == null ? "" : FastJsonUtil.toJson(reqHeader));
			task.setReqContent(reqContent);
			task.setStartTime(DateUtil.datetime2Str(startTime));
			task.setEndTime(DateUtil.datetime2Str(endTime));
			task.setOptNo(0); // 初始化为0
			task.setMaxNo(payConstants.getMaxNo()); // 最大执行次数

			saveNotifyTask(task);
		} catch (Exception e) {
			logger.error(Log.op("FuiouDepositCommonServiceImpl.saveNotifyTask").msg("保存富友存管异步通知任务异常").kv("merchantCode", merchantCode)
					.kv("busiId", busiId).kv("busiType", busiType.getValue()).toString(), e);
		}
	}

	@Override
	public void saveNotifyTask(FuiouNotifyTask task) {
		if (task == null) {
			return;
		}

		if (StringUtils.isBlank(task.getStartTime())) {
			task.setStartTime(DateUtil.getCurrentDateTime());
		}

		task.setState(TaskStateEnum.ACTIVE.getValue());
		task.setCreateTime(DateUtil.getCurrentDateTime());

		try {
			// 将异步通知持久化到数据库
			fuiouNotifyTaskDao.insert(task);
		} catch (DuplicateKeyException e) {
			logger.info(Log.op("FuiouDepositCommonServiceImpl.saveNotifyTask").msg("保存富友存管异步通知主键冲突").kv("merchantCode", task.getMerchantCode())
					.kv("busiId", task.getBusiId()).kv("busiType", task.getType()).toString());

			// 更新异步通知任务
			fuiouNotifyTaskDao.updateByPrimaryKeySelective(task);
		}

		// 添加任务到调度器
		// 改成扫描机制，不再使用动态任务，since 2.0.8
		// createNotifyJob(task);
	}

	/**
	 * 创建异步通知任务
	 * 
	 * @author buyi
	 * @date 2017-09-04 14:35:55
	 * @since v2.0.0
	 * @param task
	 */
	private void createNotifyJob(FuiouNotifyTask task) {

		// 如果下次执行时间为空，且开始时间要晚于当前时间
		if (StringUtils.isBlank(task.getNextTime())) {
			if (DateUtil.str2DateTime(task.getStartTime()).after(new Date())) {
				task.setNextTime(task.getStartTime());
			}
		}

		if (StringUtils.isBlank(task.getNextTime())) {
			// 如果下次执行时间早于当前时间，则默认加500毫秒，解決quartz执行时间早于当前时间无法触发问题
			Date nextDate = new Date(System.currentTimeMillis() + 500);
			task.setNextTime(DateUtil.datetime2Str(nextDate));
		}

		if (task.getOptNo() == null) {
			task.setOptNo(0);
		}

		// 时间执行时间表达式
		String cornEx = DateUtil.date2Str(DateUtil.str2DateTime(task.getNextTime()), "s m H d M ? yyyy");

		DynamicJobVO job = new DynamicJobVO().jobName("NT-FUIOU-" + task.getBusiId() + "-" + task.getType());
		job.cronExpression(cornEx).target(FuiouDepositNotifyJob.class).addOrderData(task);

		try {
			DynamicSchedulerFactory.updateJob(job);
		} catch (SchedulerException e) {
			logger.error(Log.op("FuiouDepositCommonServiceImpl.createNotifyJob").msg("保存富友存管异步通知任务异常").kv("task", job).toString(), e);
		}
	}

	@Override
	public void saveQueryTask(String merchantCode, String busiId, FuiouBusiTypeEnum busiType) {
		try {
			FuiouQueryTask task = new FuiouQueryTask();
			task.setBusiId(busiId);
			task.setType(busiType.getValue());
			task.setMerchantCode(merchantCode);
			task.setStartTime(DateUtil.datetime2Str(DateUtil.addMinute(new Date(), payConstants.getPayQueryMinuteDelay())));// 根据配置设定开始时间
			task.setEndTime(null);
			task.setOptNo(0); // 初始化为0
			task.setMaxNo(payConstants.getMaxNo()); // 最大执行次数
			task.setCreateTime(DateUtil.getCurrentDateTime());

			saveQueryTask(task);
		} catch (Exception e) {
			logger.error(Log.op("FuiouDepositCommonServiceImpl.saveQueryTask").msg("保存富友存管查询任务异常").kv("merchantCode", merchantCode)
					.kv("busiId", busiId).kv("busiType", busiType.getValue()).toString(), e);
		}
	}

	/**
	 * 保存查询任务
	 * 
	 * @author heizq
	 * @date 2017-09-30 15:49:31
	 * @since v2.0.0
	 * @param task
	 */
	public void saveQueryTask(FuiouQueryTask task) {
		if (task == null) {
			return;
		}

		if (StringUtils.isBlank(task.getStartTime())) {
			task.setStartTime(DateUtil.getCurrentDateTime());
		}

		task.setState(TaskStateEnum.ACTIVE.getValue());
		task.setCreateTime(DateUtil.getCurrentDateTime());

		try {
			// 将异步通知持久化到数据库
			fuiouQueryTaskDao.insert(task);
		} catch (DuplicateKeyException e) {
			logger.info(Log.op("FuiouDepositCommonServiceImpl.saveQueryTask").msg("保存富友存管查询任务主键冲突").kv("merchantCode", task.getMerchantCode())
					.kv("busiId", task.getBusiId()).kv("busiType", task.getType()).toString());

			// 更新异步通知任务
			fuiouQueryTaskDao.updateState(task);
		}

		// 添加任务到调度器
		// 改成扫描机制，不再使用动态任务，since 2.0.8
		// createQueryJob(task);
	}

	/**
	 * 生成查询调度
	 * 
	 * @author heizq
	 * @date 2017-09-30 15:50:06
	 * @since v2.0.0
	 * @param task
	 */
	private void createQueryJob(FuiouQueryTask task) {

		// 如果下次执行时间为空，且开始时间要晚于当前时间
		if (StringUtils.isBlank(task.getNextTime())) {
			if (DateUtil.str2DateTime(task.getStartTime()).after(new Date())) {
				task.setNextTime(task.getStartTime());
			}
		}

		if (StringUtils.isBlank(task.getNextTime())) {
			// 如果下次执行时间早于当前时间，则默认加500毫秒，解決quartz执行时间早于当前时间无法触发问题
			Date nextDate = new Date(System.currentTimeMillis() + 500);
			task.setNextTime(DateUtil.datetime2Str(nextDate));
		}

		if (task.getOptNo() == null) {
			task.setOptNo(0);
		}

		String cornEx = DateUtil.date2Str(DateUtil.str2DateTime(task.getNextTime()), "s m H d M ? yyyy");

		DynamicJobVO job = new DynamicJobVO().jobName("QT-FUIOU-" + task.getBusiId() + "-" + task.getType());
		job.cronExpression(cornEx).target(FuiouDepositQueryJobDispatcher.class).addOrderData(task);

		// DynamicJobVO dynamicJob = new DynamicJobVO(task);
		// // 调度触发器
		// dynamicJob.target(FuiouDepositQueryJobDispatcher.class);
		//
		// dynamicJob.addOrderData(task);
		// dynamicJob.cronExpression(DateUtil.date2Str(DateUtil.str2DateTime(task.getNextTime()), "s m H d M ? yyyy"));

		try {
			DynamicSchedulerFactory.registerJob(job);
		} catch (SchedulerException e) {
			throw new IllegalStateException(e);
		} finally {
			logger.info("【添加任务】{}", task);
			logger.info("【添加Quartz】{}", job);
		}
	}
}
